﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.Xml;

namespace ULSLogParser
{
    public class Parser
    {
        #region Constants
        //General constants
        private const int  MESSAGE_MAX_LEN = 300;
        //ULS Logs driven constants
        public const string COL_MESSAGE_TEXT = "Message";
        public const string COL_TIME_STAMP = "Timestamp";
        public const string COL_LEVEL = "Level";
        //Control columns defined in the ULSLogParser
        public const string COL_ID = "ID";
        public const string COL_PARENT_ID = "ParentID";
        public const string COL_COUNT = "Count";
        public const string COL_GENERIC = "Generic";
        
        #endregion
        
        public static DataTable OpenTabFile(string FileName, string DataTitle)
        {
            if (string.IsNullOrEmpty(FileName))
                throw new ArgumentException("Parameter FileName may not be null or empty.");
            string FileText = "";
            string[] Header = null;
            StreamReader SR = null;
            try
            {
                SR = System.IO.File.OpenText(FileName);
                FileText = SR.ReadToEnd();
                Header = VerifyLogFile(FileText);
            }
            catch (Exception)
            {
                if(SR != null)
                SR.Close();
                //string ErrorMessage = "Error happened while opening file '{0}'.\nError Details:\n{1}";
                //MessageBox.Show(string.Format(ErrorMessage, FileName, Ex.Message), "Open file error", MessageBoxButton.OK, MessageBoxImage.Error);
                throw;
            }
            DataTable LogFileData = new DataTable(DataTitle);
            //Add Control columns
            DataColumn MessageID = new DataColumn(COL_ID,typeof(int));
            MessageID.AutoIncrementSeed = 0;
            MessageID.AutoIncrement = true;
            MessageID.Unique = true;
            LogFileData.Columns.Add(MessageID);
            LogFileData.PrimaryKey = new DataColumn[] { MessageID };

            //Read Headers
            foreach (string head in Header)
            {
                LogFileData.Columns.Add(head.Trim());
            }
            
            //Add Control Columns
            LogFileData.Columns.Add(COL_COUNT);
            LogFileData.Columns.Add(COL_PARENT_ID);
            LogFileData.Columns.Add(COL_GENERIC);

            //Read logs
            string[] Lines = FileText.Split('\n');
            for (int i = 1; i < Lines.Length; i++)
            {
                if (string.IsNullOrEmpty(Lines[i])) continue;
                string[] rows = Lines[i].Split('\t');
                DataRow NewRow = LogFileData.NewRow();
                for (int x = 0; x < rows.Length; x++)
                    NewRow[x + 1] = rows[x];
                //Set count to default value 1
                NewRow[COL_COUNT] = 1;
                NewRow[COL_PARENT_ID] =-1;
                NewRow[COL_GENERIC] = "";
                LogFileData.Rows.Add(NewRow);
            }


            return LogFileData;
        }
        private static string[] VerifyLogFile(string FileText)
        {
            if (string.IsNullOrEmpty(FileText)) throw new Exception("Invalid file format. The file you are trying to open is empty"); ;
            int FirstLineEnds = FileText.IndexOf('\n');
            if (FirstLineEnds <= 0) throw new Exception("Invalid file format");
            string Header = FileText.Substring(0, FirstLineEnds + 1);
            return Header.Split('\t');
        }
        public static void ConnectLogs(DataTable Data)
        {
            if (Data == null) return;
            Debug.WriteLine("Total Records Before 'ConnectLogs'=" + Data.Rows.Count.ToString());
            for (int i = 0; i < Data.Rows.Count; i++)
            {
                if (Data.Rows[i][COL_TIME_STAMP].ToString().Contains("*") && i>=0)
                {
                    string OldMessage = Data.Rows[i - 1][COL_MESSAGE_TEXT].ToString();
                    string NewMessage = OldMessage + Data.Rows[i][COL_MESSAGE_TEXT].ToString();
                    //Connect two messages and remove the dots
                    Data.Rows[i - 1][COL_MESSAGE_TEXT] = NewMessage.Replace("......", "");

                    //remove the extra row
                    Data.Rows.RemoveAt(i); i--;
                }
            }
            Debug.WriteLine("Total Records After'ConnectLogs'=" + Data.Rows.Count.ToString());
        }
        private static TreeNode FindTreeNodeLogByLogID(TreeNode Tree, string LogID)
        {
            foreach (TreeNode Node in Tree.Nodes)
            {
                if (Node.Tag != null &&
                    Node.Tag.GetType() == typeof(DataRow) &&
                    ((DataRow)Node.Tag)[COL_ID].ToString() == LogID)
                {
                    return Node;
                }
            }
            return null;
        }
        public static TreeNode FindFirstTreeNodeByNodeName(TreeNode Tree, string NodeName)
        {
            TreeNode[] Results = Tree.Nodes.Find(NodeName, true);
            if (Results != null && Results.Length > 0)
                return Results[0];
            return null;
        }
        public static TreeNode FindFirstTreeNodeByNodeName(TreeView Tree, string NodeName)
        {
            TreeNode[] Results = Tree.Nodes.Find(NodeName, true);
            if (Results != null && Results.Length > 0)
                return Results[0];
            return null;
        }
        public static TreeNode FindFirstNodeByNodeText(TreeView Tree, string SearchTxt)
        {
            foreach (TreeNode node in Tree.Nodes)
            {
                if (string.Compare(node.Text, SearchTxt, true) == 0)
                    return node;
                else
                    return FindNodeByText(node, SearchTxt);
            }
            return null;
        }

        private static TreeNode FindNodeByText(TreeNode node, string SearchTxt)
        {
            if (string.Compare(node.Text, SearchTxt, true) == 0)
                return node;
            foreach (TreeNode Nodes in node.Nodes)
            {
                return FindNodeByText(Nodes, SearchTxt);
            }
            return null;
        }
        private static bool IsGenericHeader(TreeNode LogNode)
        {
            return LogNode.Tag != null &&
                    LogNode.Tag.GetType() == typeof(DataRow) &&
                    ((DataRow)LogNode.Tag)[COL_GENERIC].ToString() != "";
         
        }
        private static TreeNode CopyDataRowLogToTreeNodeLog(DataTable OriginalDataSource,DataRow LogRecord, TreeNode TargetTree, IconMappingHandler iconMappingHandler)
        {
            string ID = LogRecord[COL_ID].ToString();
            string Message = LogRecord[COL_MESSAGE_TEXT].ToString();
            string Level = LogRecord[COL_LEVEL].ToString();
            string ParentID = LogRecord[COL_PARENT_ID].ToString();
            string Count = LogRecord[COL_COUNT].ToString();

            //if the message is a head of a logs group
            if (Count != "1")
            {
                TreeNode NewNode = null;
                NewNode = new TreeNode(Count + " = " + Message);
                if(iconMappingHandler!=null)
                NewNode.ImageIndex = iconMappingHandler(Level);
                NewNode.Tag = OriginalDataSource.Rows.Find(int.Parse(ID));
                TargetTree.Nodes.Add(NewNode);

                //Add the group header as the first child element

                TreeNode NewSubNode = new TreeNode(LogRecord[COL_TIME_STAMP].ToString());
                if (iconMappingHandler != null)
                    NewSubNode.ImageIndex = iconMappingHandler(Level);
                NewSubNode.Tag = NewNode.Tag;
                NewNode.Nodes.Add(NewSubNode);

            }
            else
            {
                TreeNode GroupHeaderNode = FindTreeNodeLogByLogID(TargetTree, ParentID);
                TreeNode NewNode = new TreeNode();
                if (IsGenericHeader(GroupHeaderNode))
                    NewNode.Text = Message;
                else
                    NewNode.Text = LogRecord[COL_TIME_STAMP].ToString(); ;
                if (iconMappingHandler != null)
                NewNode.ImageIndex = iconMappingHandler(Level);
                NewNode.Tag = OriginalDataSource.Rows.Find(int.Parse(ID));
                GroupHeaderNode.Nodes.Add(NewNode);
            }


            return TargetTree;
        }
        public delegate int IconMappingHandler(string CatText);
        public static TreeNode GenerateSummaryAI(DataTable Data, IconMappingHandler iconMappingHandler, decimal MatchErrorPrecentageAllowed, string RootNodeTitle, string RootNodeTooltip)
        {
            //check for null params
            if(Data == null)
                throw new ArgumentException(
                  "Parameter Data may not be null.");
            if (MatchErrorPrecentageAllowed >100 || 
                MatchErrorPrecentageAllowed < 0)
                throw new ArgumentOutOfRangeException(
                  "Parameter MatchErrorPrecentageAllowed should be between 0 and 100.");
            
            DataTable tempTable = Data.Copy();
            TreeNode SumTree = new TreeNode(RootNodeTitle);
            SumTree.ToolTipText = RootNodeTooltip;
            while (tempTable.Rows.Count > 0)
            {
                string Count = tempTable.Rows[0][COL_COUNT].ToString();
                string ParentID = tempTable.Rows[0][COL_PARENT_ID].ToString();
                //Skip group logs
                if (Count != "1" || ParentID != "-1")
                {
                    //Add to the tree in the appropriate location
                    CopyDataRowLogToTreeNodeLog(Data,tempTable.Rows[0], SumTree, iconMappingHandler);
                    tempTable.Rows.RemoveAt(0);
                    continue;
                }
                string ID = tempTable.Rows[0][COL_ID].ToString();
                string Message = tempTable.Rows[0][COL_MESSAGE_TEXT].ToString();
                string Level = tempTable.Rows[0][COL_LEVEL].ToString();
                DataRow OriginRow = Data.Rows.Find(int.Parse(ID));
                int itemCount = 0;
                int TotalCount = tempTable.Rows.Count;
                Dictionary<string, string> SemiMatchMessages = new Dictionary<string, string>();
                tempTable = FindRowCellCount(Message, COL_MESSAGE_TEXT, tempTable, ref SemiMatchMessages, MatchErrorPrecentageAllowed);
                itemCount = TotalCount - tempTable.Rows.Count;
                
                //if the message is redundant
                if (itemCount > 1)
                {

                    TreeNode NewNode = null;
                    //if its redundant with few differences show the generic message that is common between redundant mesages
                    if (SemiMatchMessages.ContainsKey("-1"))
                    {
                        string GenericMessage = "";
                        GenericMessage = SemiMatchMessages["-1"];
                        NewNode = new TreeNode(itemCount.ToString() + " = " + ShortenString(GenericMessage, MESSAGE_MAX_LEN));
                        if (iconMappingHandler != null)
                        NewNode.ImageIndex = iconMappingHandler(Level);
                        //Update the origin row count column value
                        OriginRow[COL_COUNT] = itemCount;
                        OriginRow[COL_GENERIC] = GenericMessage;
                        NewNode.Tag = OriginRow;

                        ////add the first found as the first node
                        TreeNode NewSubNode = new TreeNode(ShortenString(Message, MESSAGE_MAX_LEN));
                        if (iconMappingHandler != null)
                        NewSubNode.ImageIndex = iconMappingHandler(Level);
                        NewSubNode.Tag = OriginRow;
                        OriginRow[COL_PARENT_ID] = ID;
                        NewNode.Nodes.Add(NewSubNode);
                    }
                    else
                    {

                        NewNode = new TreeNode(itemCount.ToString() + " = " + ShortenString(Message, MESSAGE_MAX_LEN));
                        if (iconMappingHandler != null)
                        NewNode.ImageIndex = iconMappingHandler(Level);
                        NewNode.Tag = Data.Rows.Find(int.Parse(ID));


                    }
                    foreach (KeyValuePair<string, string> item in SemiMatchMessages)
                    {
                        if (item.Key == "-1") continue;
                        TreeNode NewSubNode = new TreeNode(item.Value);
                        DataRow OrgRow = Data.Rows.Find(int.Parse(item.Key));
                        if (iconMappingHandler != null)
                        NewSubNode.ImageIndex = iconMappingHandler(Level);
                        NewSubNode.Tag = OrgRow;
                        //Update the ParentID to bind this child log with its parent log
                        OrgRow[COL_PARENT_ID] = ID;
                        NewNode.Nodes.Add(NewSubNode);

                    }
                    SumTree.Nodes.Add(NewNode);
                }
                else
                {
                    TreeNode NewNode = new TreeNode(itemCount.ToString() + " = " + ShortenString(Message, MESSAGE_MAX_LEN));
                    if(iconMappingHandler!=null)
                    NewNode.ImageIndex = iconMappingHandler(Level);
                    NewNode.Tag = Data.Rows.Find(int.Parse(ID));

                    foreach (KeyValuePair<string, string> item in SemiMatchMessages)
                    {
                        if (item.Key == "-1") continue;
                        DataRow OriginalRow = Data.Rows.Find(int.Parse(item.Key));
                        TreeNode NewSubNode = new TreeNode(item.Value);
                        if (iconMappingHandler != null)
                        NewSubNode.ImageIndex = iconMappingHandler(Level);
                        NewSubNode.Tag = OriginalRow;
                        //Update the ParentID to bind this child log with its parent log
                        OriginalRow[COL_PARENT_ID] = ID;
                        NewNode.Nodes.Add(NewSubNode);
                    }
                    SumTree.Nodes.Add(NewNode);
                }
            }

            return SumTree;
        }
        
        public static TreeNode GenerateSummary(DataTable Data, IconMappingHandler iconMappingHandler, string RootNodeTitle, string RootNodeTooltip)
        {
            DataTable tempTable = Data.Copy(); ;
            TreeNode SumTree = new TreeNode(RootNodeTitle);
            SumTree.ToolTipText = RootNodeTooltip;
            while(tempTable.Rows.Count > 0)
            {
                string ID = tempTable.Rows[0][COL_ID].ToString();
                string Message = tempTable.Rows[0][COL_MESSAGE_TEXT].ToString();
                string Level = tempTable.Rows[0][COL_LEVEL].ToString();
                int itemCount = 0;
                int TotalCount = tempTable.Rows.Count;
                Dictionary<string, string> MatchMessages = new Dictionary<string, string>();
                tempTable = FindRowCellCount(Message, COL_MESSAGE_TEXT, tempTable, ref MatchMessages, 0m);
                itemCount = TotalCount - tempTable.Rows.Count;
                //if the message is redundant
                if (itemCount > 1)
                {

                    TreeNode NewNode = null;
                    DataRow OriginRow = Data.Rows.Find(int.Parse(ID));

                    //Update the origin row count column value
                    OriginRow[COL_COUNT] = itemCount;
                    NewNode = new TreeNode(itemCount.ToString() + " = " + ShortenString(Message,MESSAGE_MAX_LEN));
                    if(iconMappingHandler != null)
                    NewNode.ImageIndex = iconMappingHandler(Level);
                    NewNode.Tag = OriginRow;

                    //Add the group header as the first child element
                    TreeNode NewSubNode = new TreeNode(ShortenString(Message, MESSAGE_MAX_LEN));
                    if (iconMappingHandler != null)
                    NewSubNode.ImageIndex = iconMappingHandler(Level);
                    NewSubNode.Tag = OriginRow;

                    //Add the redundant messages references as sub nodes
                    foreach (KeyValuePair<string, string> item in MatchMessages)
                    {
                        if (item.Key == "-1") continue;
                        DataRow OriginalRow = Data.Rows.Find(int.Parse(item.Key));
                        NewSubNode = new TreeNode(OriginalRow[COL_TIME_STAMP].ToString());
                        if (iconMappingHandler != null)
                        NewSubNode.ImageIndex = iconMappingHandler(Level);
                        NewSubNode.Tag = OriginalRow;
                        NewNode.Nodes.Add(NewSubNode);
                        //Update the ParentID to bind this child log with its parent log
                        OriginalRow[COL_PARENT_ID] = ID;
                    }
                    SumTree.Nodes.Add(NewNode);
                }
                else
                {
                    TreeNode NewNode = new TreeNode(ShortenString(Message, MESSAGE_MAX_LEN));
                    if (iconMappingHandler != null)
                    NewNode.ImageIndex = iconMappingHandler(Level);
                    NewNode.Tag = Data.Rows.Find(int.Parse(ID));
                    SumTree.Nodes.Add(NewNode);
                }
            }

            return SumTree;
        }
        #region ExportToXml
        public static bool ExportSummary(TreeNode SummaryNode, string FileName)
        {
            StreamWriter sr;
            sr = new StreamWriter(FileName, false, System.Text.Encoding.UTF8);
            //Write the header
            sr.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
            sr.WriteLine("<?xml-stylesheet type=\"text/xsl\" href=\"ReportFormater.xsl\"?>");
            //Write our root node
            sr.WriteLine("<LogFile Title=\"" + System.Web.HttpUtility.HtmlEncode(SummaryNode.Text) + "\">");
            foreach (TreeNode node in SummaryNode.Nodes)
                saveNode(node,sr);
            //Close the root node
            sr.WriteLine("</LogFile>");
            sr.Close();
            return true;
        }
        private static void saveNode(TreeNode TNode, StreamWriter sr)
        {
            
                //If we have child nodes, we'll write 
                //a parent node, then iterrate through
                //the children
            if (TNode.Nodes.Count > 0)
            {
                sr.WriteLine("<LogHeader Title=\"" + System.Web.HttpUtility.HtmlEncode(ShortenString(TNode.Text, MESSAGE_MAX_LEN)) + "\">");
                foreach (TreeNode node in TNode.Nodes)
                    saveNode(node, sr);
                sr.WriteLine("</LogHeader>");
            }
            else //No child nodes, so we just write the text
            {
                if (TNode.Tag != null && TNode.Tag.GetType() == typeof(DataRow))
                {
                    DataRow SelectedNode = (DataRow)TNode.Tag;
                    sr.WriteLine(ConvertTreeNodeIntoXmlNode(TNode, SelectedNode, COL_MESSAGE_TEXT));
                }
                else
                    sr.WriteLine("<" + System.Web.HttpUtility.HtmlEncode(TNode.Text) + "/>");

            }
            
        }
        private static string ConvertTreeNodeIntoXmlNode(TreeNode TNode, DataRow DRow, string DataColumnName)
        {
            //Creat attributes
            StringBuilder Attributes = new StringBuilder();
            //Add Node Title 
            Attributes.AppendFormat("Title=\"{0}\" ", ShortenString(System.Web.HttpUtility.HtmlEncode(TNode.Text), 50));
            foreach (DataColumn Col in DRow.Table.Columns)
            {
                if (Col.Caption == DataColumnName) continue;
                string ColVal = DRow[Col].ToString().Trim();
                Attributes.AppendFormat("{0}=\"{1}\" ", Col.Caption, System.Web.HttpUtility.HtmlEncode(ColVal));
            }
            return CreateXmlNode("LogLine", Attributes, System.Web.HttpUtility.HtmlEncode(DRow[DataColumnName].ToString()));
        }
        private static string CreateXmlNode(string XmlTagName, string Title, string Content)
        {
            string NodeString = "<{2} {0}>{1}</{2}>";

            //Creat attributes
            StringBuilder Attributes = new StringBuilder();
            //Add Node Title 
            Attributes.AppendFormat("Title=\"{0}\" ", System.Web.HttpUtility.HtmlEncode(Title));

            return string.Format(NodeString, Attributes, System.Web.HttpUtility.HtmlEncode(Content), XmlTagName);
        }
        private static string CreateXmlNode(string XmlTagName, string Title,
            Dictionary<string,string> Attributes, string Content)
        {
            string NodeString = "<{2} {0}>{1}</{2}>";

            //Creat attributes
            StringBuilder AttributesStr = new StringBuilder();
            //Add Node Title 
            AttributesStr.AppendFormat("Title=\"{0}\" ", System.Web.HttpUtility.HtmlEncode(Title));
            foreach (KeyValuePair<string,string> Att in Attributes)
            {
                AttributesStr.AppendFormat("{0}=\"{1}\" ", Att.Key, System.Web.HttpUtility.HtmlEncode(Att.Value));
            }


            return string.Format(NodeString, AttributesStr, System.Web.HttpUtility.HtmlEncode(Content), XmlTagName);
        }
        private static string CreateXmlNode(string XmlTagName,
            Dictionary<string, string> Attributes, string Content)
        {
            string NodeString = "<{2} {0}>{1}</{2}>";

            //Creat attributes
            StringBuilder AttributesStr = new StringBuilder();
            //Add Node Title 
            foreach (KeyValuePair<string, string> Att in Attributes)
            {
                AttributesStr.AppendFormat("{0}=\"{1}\" ", Att.Key, System.Web.HttpUtility.HtmlEncode(Att.Value));
            }
            return string.Format(NodeString, AttributesStr, System.Web.HttpUtility.HtmlEncode(Content), XmlTagName);
        }
             private static string CreateXmlNode(string XmlTagName,
            StringBuilder Attributes, string Content)
        {
            string NodeString = "<{2} {0}>{1}</{2}>";

            return string.Format(NodeString, Attributes, System.Web.HttpUtility.HtmlEncode(Content), XmlTagName);
        }
        #endregion
        public static string IncreamentSafeFileName(string SafeFileName)
        {
            int Count = 0;
            int DotLocation = SafeFileName.LastIndexOf('.');
            string FileNameWithoutExtension = "";
            if (DotLocation > 0)
                FileNameWithoutExtension = SafeFileName.Substring(0, DotLocation);
            else//Failed to find the extension. Return a new unique name
                return Guid.NewGuid().ToString() + ".log";
            //Parse the number at the end
            int NumberLocation = -1;
            for (int i = FileNameWithoutExtension.Length - 1; i >= 0; i--)
            {
                if (!char.IsDigit(FileNameWithoutExtension[i]))
                {
                    NumberLocation = i + 1;
                    break;
                }
            }
            //if the file name has no numbers yet
            if (NumberLocation >= FileNameWithoutExtension.Length)
                return SafeFileName.Replace(FileNameWithoutExtension, FileNameWithoutExtension + "1");

            //Number is found. Icreament the number and return the new name
            int.TryParse(FileNameWithoutExtension.Substring(NumberLocation), out Count);
            Count++;
            return SafeFileName.Replace(FileNameWithoutExtension, FileNameWithoutExtension.Substring(0, NumberLocation) + Count);
        }
        private static string ShortenString(string Textstr,int MaxSize)
        {
            if (string.IsNullOrEmpty(Textstr)) return "";
            if (Textstr.Length > MaxSize)
            {
                return Textstr.Substring(0, MaxSize) + "...";
            }
            return Textstr;
        }
        private static DataTable FindRowCellCount(string Message, string RowName, DataTable Data, ref Dictionary<string, string> SemiMatchMessages, decimal MatchErrorPrecentageAllowed)
        {
            SemiMatchMessages = new Dictionary<string, string>();
            string GenericMessage = Message;
            bool SemiMatchingFound = false;
            if (MatchErrorPrecentageAllowed <= 0m) //No AI implemented just regular string matching
            {
                for (int i = 0; i < Data.Rows.Count; i++)
                {
                    string OrgMessage = Data.Rows[i][RowName].ToString();
                    string ID = Data.Rows[i][COL_ID].ToString();
                    if (OrgMessage == Message)
                    {
                        Data.Rows.RemoveAt(i);
                        SemiMatchMessages.Add(ID, OrgMessage);
                        i--;
                    }
                }
            }
            else
            {

                
                for (int i = 0; i < Data.Rows.Count; i++)
                {
                    string OrgMessage = Data.Rows[i][RowName].ToString();
                    string ID = Data.Rows[i][COL_ID].ToString();
                    if (OrgMessage == Message)
                    {
                        Data.Rows.RemoveAt(i);
                        i--;
                    }//CompoundMessage
                    else if (MatchStringAI1(OrgMessage, Message, MatchErrorPrecentageAllowed, ref GenericMessage))
                    {
                        SemiMatchMessages.Add(ID, OrgMessage);
                        Data.Rows.RemoveAt(i);
                        i--;
                        SemiMatchingFound = true;
                    }
                }
                if (SemiMatchingFound)
                    SemiMatchMessages.Add("-1", GenericMessage);
            }
            return Data;

        }
        //By letters count
        private static bool MatchStringAI(string A, string B,decimal Precentage)
        {
            
            string[] Awords = ParseWords(A.ToLower());
            string[] Bwords = ParseWords(B.ToLower());
            int LargestCount = 0;
            //var result = new string[]{};
            List<string> Result = new List<string>();
            if (A.Length >= B.Length)
            {
                LargestCount = B.Length;
                var result = Awords.Except(Bwords);
                Result = result.ToList<string>();
            }
            else
            {
                LargestCount = A.Length;
                var result = Bwords.Except(Awords);
                Result = result.ToList<string>();
            }
            int DifferenceCount = 0;
            foreach (var item in Result)
            {
                DifferenceCount += item.Length;
            }
            
            decimal ResultVal = Convert.ToDecimal(DifferenceCount) / Convert.ToDecimal(LargestCount) * 100m;
            if (Precentage >= ResultVal) 
                return true;
            return false;
        }
        //By word count
        private static bool MatchStringAI1(string A, string B, decimal Precentage, ref string GenericMessage)
        {

            string[] Awords = ParseWords(A);
            string[] Bwords = ParseWords(B);
            //string TempGenericMessage = "";
            int LargestCount = 0;
            List<string> Result = new List<string>();
            if (Awords.Length >= Bwords.Length)
            {
                LargestCount = Bwords.Length;
                //TempGenericMessage = A;
                var result = Awords.Except(Bwords);
                Result = result.ToList<string>();
            }
            else
            {
                LargestCount = Awords.Length;
                //TempGenericMessage = B;
                var result = Bwords.Except(Awords);
                Result = result.ToList<string>();
            }
            
            decimal ResultVal = Convert.ToDecimal(Result.Count) / Convert.ToDecimal(LargestCount) * 100m;
            if (Precentage >= ResultVal)
            {
                List<string> Result1 = new List<string>();
                if (Awords.Length >= Bwords.Length)
                {
                    
                    var result = Bwords.Except(Awords);
                    Result1 = result.ToList<string>();
                }
                else
                {

                    var result = Awords.Except(Bwords);
                    Result1 = result.ToList<string>();
                }

                //Create the generic message
                foreach (string item in Result)
                {
                    if (!string.IsNullOrEmpty(item) && item.Length>2)
                        GenericMessage = GenericMessage.Replace(item, "XXXXX");
                }
                foreach (string item in Result1)
                {
                    if (!string.IsNullOrEmpty(item) && item.Length > 2)
                        GenericMessage = GenericMessage.Replace(item, "XXXXX");
                }
               // GenericMessage = TempGenericMessage;
                return true;
            }
            return false;
        }
        private static string[] ParseWords(string Sentance)
        {
            return Sentance.Split(' ','"',',','/','@',':');
        }






    }
    public class FilterRule
    {
        public int ID { get; set; }
        public string ColumnName { get; set; }
        public Op Operator { get; set; }
        public string Value { get; set; }
        public string ColumnType { get; set; }
        public FilterRule()
        {
            ID = -1;
            ColumnName = "";
            Operator = Op.Equal;
            Value = "";
            ColumnType = "Text";
        }
        public FilterRule(int Id, string columnName, Op operatoR, string valuE, string columnType)
        {
            ID = Id;
            ColumnName = columnName;
            Operator = operatoR;
            Value = valuE;
            ColumnType = columnType;
        }
        public FilterRule(string columnName, Op operatoR, string valuE)
        {
            ID = -1;
            ColumnName = columnName;
            Operator = operatoR;
            Value = valuE;
            ColumnType = "Text";
        }
        public static FilterRule GetFilterRule(TreeNode Node)
        {
            if (Node != null &&
                Node.Tag != null &&
                Node.Tag.GetType() == typeof(FilterRule))
            {

                return Node.Tag as FilterRule;
            }
            return null;
        }
        public override string ToString()
        {
            string OpStr = "";
            switch (Operator)
            {
                case Op.LessThan:
                    OpStr = "<";
                    break;
                case Op.LessThanOrEqual:
                    OpStr = "<=";
                    break;
                case Op.GreaterThan:
                    OpStr = ">";
                    break;
                case Op.GreaterThanOrEqual:
                    OpStr = ">=";
                    break;
                case Op.Equal:
                    OpStr = "=";
                    break;
                case Op.NotEqual:
                    OpStr = "<>";
                    break;
            }
            return string.Format("{0} {1} {2}", ColumnName, OpStr, Value);
        }

    }
    public enum Op
    {
        LessThan,
        LessThanOrEqual,
        GreaterThan,
        GreaterThanOrEqual,
        Equal,
        NotEqual
    }
}
